package cn.jly.mybatis.plugins;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Statement;
import java.util.Properties;

/**
 * @author lanyangji
 * @description 自定义插件
 * @date 2020/11/19 上午 10:57
 */
@Intercepts({
        @Signature(type = StatementHandler.class, method = "parameterize", args = Statement.class)
})
public class MyFirstPlugin implements Interceptor {

    /**
     * 拦截目标对象的目标方法的执行
     * <p>
     * 包装顺序按照config.xml中配置顺序，但是拦截顺序是后包装的先执行
     *
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("MyFirstPlugin.intercept");

        System.out.println("当前拦截到的对象 --> " + invocation.getTarget());

        // 拿到statementHandler中parameterHandler中的parameterObject值
        // 拿到目标对象的元数据
        final MetaObject metaObject = SystemMetaObject.forObject(invocation.getTarget());
        // 获取指定属性的值
        final Object value = metaObject.getValue("parameterHandler.parameterObject");
        System.out.println("sql语句用的参数为 --> " + value);
        // 动态改变sql运行的参数
        if ("杨".equals(value)) {
            metaObject.setValue("parameterHandler.parameterObject", "洋");
        }

        // 执行目标方法
        final Object res = invocation.proceed();

        // 返回执行后的返回值
        return res;
    }

    /**
     * 插件包装目标对象，即为目标对象创建一个代理对象
     * <p>
     * 包装顺序按照config.xml中配置顺序，但是拦截顺序是后包装的先执行。
     * 本质是将第一个拦截器包装后的对象交给后面的拦截器继续包装
     * <p>
     * 多个插件就会产生多层代理
     *
     * @param target
     * @return
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("MyFirstPlugin.plugin --> " + target);

        // 借助Plugin类的wrap方法类使用当前拦截器的interceptor拦截并包装目标对象
        final Object wrap = Plugin.wrap(target, this);
        System.out.println("wrap = " + wrap);
        // 返回为目标对象创建的动态代理
        return wrap;
    }

    /**
     * 将插件注册时的properties属性设置进来
     *
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件的配置信息 --> " + properties);
    }
}
